package com.alm.handle.service.impl;

import com.alm.common.core.domain.AjaxResult;
import com.alm.common.core.redis.RedisCache;
import com.alm.common.exception.ServiceException;
import com.alm.common.utils.SecurityUtils;
import com.alm.entity.PasingByteModel;
import com.alm.handle.core.domain.entity.AlmDevGroup;
import com.alm.handle.core.domain.entity.AlmGroupCron;
import com.alm.handle.core.domain.entity.SysDevInfo;
import com.alm.handle.core.domain.entity.rq.DevCronEditRq;
import com.alm.handle.core.domain.entity.rq.DevCronQueryRq;
import com.alm.handle.core.domain.entity.vo.DevCronVo;
import com.alm.handle.core.domain.entity.vo.DevInfoListVO;
import com.alm.handle.mapper.AlmGroupCronMapper;
import com.alm.handle.service.AlmDevCronService;
import com.alm.handle.service.AlmDevGroupService;
import com.alm.handle.service.ISysDevInfoService;
import com.alm.handle.util.*;
import com.alm.util.Misc;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;

/**
 * 设备定时任务服务实现类
 *
 * @author 詹泽峰
 * @date 2024/07/05 13:44
 */
@Service
@Slf4j
public class AlmDevCronServiceImpl implements AlmDevCronService {

    @Resource
    private RedisCache redisCache;

    @Resource
    private ISysDevInfoService sysDevInfoService;

    @Resource
    private AlmDevGroupService almDevGroupService;

    @Resource
    private AlmGroupCronMapper almGroupCronMapper;

    /**
     * 发送查询任务列表命令，若缓存中有该设备的任务列表则返回
     *
     * @param rq
     * @return com.alm.common.core.domain.AjaxResult
     * @author: 詹泽峰
     * @date: 2024/7/5 14:56
     */
    @Override
    public AjaxResult getDevCronList(DevCronQueryRq rq) {
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new ServiceException("无法获取用户信息");
        }
        String key = SoketEleKey.CRONSTATUS + rq.getMac();
        /**
         * data区内容封装
         * B4: 设置id
         * Msgid: 06 任务列表查询，详见协议
         */
        //data区设置id为"B4",Msgid为"06"
        String data = "B406";
        //调用封装命令方法
        String command = DataUtils.setCommand(rq.getMac(), rq.getDevType(), "91", data);
        //发送指令
        boolean isSuccess = SendMessage.sendMessage(ByteUtils.hexStrToBytes(command), rq.getMac());
        if (isSuccess) {
            return AjaxResult.success("查询命令发送成功");
        } else {
            return AjaxResult.error("查询命令发送失败");
        }
    }

    /**
     * 根据任务id查询任务信息
     *
     * @param rq
     * @return com.alm.common.core.domain.AjaxResult
     * @author: 詹泽峰
     * @date: 2024/7/16 15:50
     */
    @Override
    public AjaxResult getDevCronById(DevCronQueryRq rq) {
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new ServiceException("无法获取用户信息");
        }
        StringBuffer data = new StringBuffer();
        data.append("B404");
        DataUtils.appendCronData(data, "C1", Misc.int2hexStr4(rq.getCronId()).toUpperCase());
        //调用封装命令方法
        String command = DataUtils.setCommand(rq.getMac(), rq.getDevType(), "91", data.toString());
        //发送指令
        boolean isSuccess = SendMessage.sendMessage(ByteUtils.hexStrToBytes(command), rq.getMac());
        if (isSuccess) {
            return AjaxResult.success("查询命令发送成功");
        } else {
            return AjaxResult.error("查询命令发送失败");
        }
    }

    /**
     * 新增定时任务，C4的参数设置目前在前端做，C5未启用
     * C1-C9的这些参数具体信息，参见协议或CommandUtil的cronDataParse方法的注释
     *
     * @param rq
     * @return com.alm.common.core.domain.AjaxResult
     * @author: 詹泽峰
     * @date: 2024/7/10 14:47
     */
    @Override
    public AjaxResult addDevCron(DevCronEditRq rq) {
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new ServiceException("无法获取用户信息");
        }
        StringBuffer data = new StringBuffer();
        //data区设置id为"B4",Msgid为"01"
        data.append("B401");
        DataUtils.appendCronData(data, "C1", Misc.int2hexStr4(rq.getCronId()).toUpperCase());
        DataUtils.appendCronData(data, "C2", com.alm.handle.util.Misc.long2hexStr8(rq.getCronStartDateTime())
                .toUpperCase());
        DataUtils.appendCronData(data, "C3", rq.getCronFunction().toUpperCase());
        DataUtils.appendCronData(data, "C4", Misc.int2hexStr2(rq.getCronParam().length() / 2)
                .toUpperCase() + rq.getCronParam().toUpperCase());
//        DataUtils.appendCronData(data, "C5", rq.getCronParam());
        DataUtils.appendCronData(data, "C6", Misc.int2hexStr2(rq.getCycleType()).toUpperCase());
        DataUtils.appendCronData(data, "C7", com.alm.handle.util.Misc.long2hexStr8(rq.getCronEndDateTime())
                .toUpperCase());
        DataUtils.appendCronData(data, "C8", com.alm.handle.util.Misc.long2hexStr8(rq.getCycleInterval())
                .toUpperCase());
        DataUtils.appendCronData(data, "C9", Misc.int2hexStr2(rq.getCronSwitch()).toUpperCase());

        String command = DataUtils.setCommand(rq.getMac(), rq.getDevType(), "91", data.toString());
        boolean isSuccess = SendMessage.sendMessage(ByteUtils.hexStrToBytes(command), rq.getMac());
        if (isSuccess) {
            return AjaxResult.success("新增命令发送成功");
        } else {
            return AjaxResult.error("新增命令发送失败");
        }
    }

    /**
     * 删除指定id的定时任务
     *
     * @param rq
     * @return com.alm.common.core.domain.AjaxResult
     * @author: 詹泽峰
     * @date: 2024/7/10 16:53
     */
    @Override
    public AjaxResult delDevCron(DevCronEditRq rq) {
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new ServiceException("无法获取用户信息");
        }
        StringBuffer data = new StringBuffer();
        //拼接data和命令，发送命令
        data.append("B402");
        DataUtils.appendCronData(data, "C1", Misc.int2hexStr4(rq.getCronId()).toUpperCase());
        String command = DataUtils.setCommand(rq.getMac(), rq.getDevType(), "91", data.toString());
        boolean isSuccess = SendMessage.sendMessage(ByteUtils.hexStrToBytes(command), rq.getMac());
        if (isSuccess) {
            String key = SoketEleKey.CRONSTATUS + rq.getMac();
            List<DevCronVo> cronList = redisCache.getCacheList(key);
            for (DevCronVo cronVo : cronList) {
                if (cronVo.getCronId().equals(rq.getCronId())) {
                    redisCache.delCacheList(key, cronVo);
                }
            }
            return AjaxResult.success("删除命令发送成功");
        } else {
            return AjaxResult.error("删除命令发送失败");
        }
    }

    /**
     * 修改指定id的定时任务
     *
     * @param rq
     * @return com.alm.common.core.domain.AjaxResult
     * @author: 詹泽峰
     * @date: 2024/7/11 13:52
     */
    @Override
    public AjaxResult editDevCron(DevCronEditRq rq) {
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new ServiceException("无法获取用户信息");
        }
        StringBuffer data = new StringBuffer();
        //data区设置id为"B4",Msgid为"03"
        data.append("B403");
        DataUtils.appendCronData(data, "C1", Misc.int2hexStr4(rq.getCronId()).toUpperCase());
        DataUtils.appendCronData(data, "C2", com.alm.handle.util.Misc.long2hexStr8(rq.getCronStartDateTime())
                .toUpperCase());
        DataUtils.appendCronData(data, "C3", rq.getCronFunction().toUpperCase());
        DataUtils.appendCronData(data, "C4", Misc.int2hexStr2(rq.getCronParam().length() / 2)
                .toUpperCase() + rq.getCronParam().toUpperCase());
//        DataUtils.appendCronData(data, "C5", rq.getCronParam());
        DataUtils.appendCronData(data, "C6", Misc.int2hexStr2(rq.getCycleType()).toUpperCase());
        DataUtils.appendCronData(data, "C7", com.alm.handle.util.Misc.long2hexStr8(rq.getCronEndDateTime())
                .toUpperCase());
        DataUtils.appendCronData(data, "C8", com.alm.handle.util.Misc.long2hexStr8(rq.getCycleInterval())
                .toUpperCase());
        DataUtils.appendCronData(data, "C9", Misc.int2hexStr2(rq.getCronSwitch()).toUpperCase());
        String command = DataUtils.setCommand(rq.getMac(), rq.getDevType(), "91", data.toString());
        boolean isSuccess = SendMessage.sendMessage(ByteUtils.hexStrToBytes(command), rq.getMac());
        if (isSuccess) {
            return AjaxResult.success("修改命令发送成功");
        } else {
            return AjaxResult.error("修改命令发送失败");
        }
    }

    /**
     * 收到数据区id为B4的数据包后，更新缓存Redis的任务列表
     *
     * @param header
     * @return void
     * @author: 詹泽峰
     * @date: 2024/7/9 18:15
     */
    @Override
    public void updateRedisCronList(PasingByteModel.Header header) throws Exception {
        //Data解析
        String data = ByteUtils.arrayToString(header.getIntData(), 0, header.getIntData().size());
        DevCronVo devCronVo = DataUtils.parseCronData(data);
        //刷新redis
        String key = SoketEleKey.CRONSTATUS + header.getDvcId();
        List<DevCronVo> cronList = redisCache.getCacheList(key);
        boolean isRepeated = false;
        for (int i = 0; i < cronList.size(); i++) {
            if (cronList.get(i).getCronId().intValue() == devCronVo.getCronId().intValue()) {
                cronList.remove(cronList.get(i));
                cronList.add(i, devCronVo);
                isRepeated = true;
            }
        }
        if (!isRepeated) {
            cronList.add(devCronVo);
        }
        redisCache.deleteObject(key);
        redisCache.setCacheList(key, cronList);
        redisCache.expire(key, 3600);
    }

    /**
     * 修改任务启用/禁用状态
     *
     * @param rq
     * @return void
     * @author: 詹泽峰
     * @date: 2024/7/16 14:49
     */
    @Override
    public AjaxResult editCronSwitch(DevCronEditRq rq) {
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new ServiceException("无法获取用户信息");
        }
        StringBuffer data = new StringBuffer();
        data.append("B408");
        DataUtils.appendCronData(data, "C1", Misc.int2hexStr4(rq.getCronId()).toUpperCase());
        DataUtils.appendCronData(data, "C9", Misc.int2hexStr2(rq.getCronSwitch()).toUpperCase());
        String command = DataUtils.setCommand(rq.getMac(), rq.getDevType(), "91", data.toString());
        boolean isSuccess = SendMessage.sendMessage(ByteUtils.hexStrToBytes(command), rq.getMac());
        if (isSuccess) {
            return AjaxResult.success("修改启用/禁用命令发送成功");
        } else {
            return AjaxResult.error("修改启用/禁用命令发送失败");
        }
    }


    /**
     * 前端轮询该服务进行表格刷新，实时刷新表格数据
     *
     * @param rq
     * @return com.alm.common.core.domain.AjaxResult
     * @author: 詹泽峰
     * @date: 2024/7/16 14:42
     */
    @Override
    public AjaxResult refresh(DevCronQueryRq rq) {
        String key = SoketEleKey.CRONSTATUS + rq.getMac();
        List<DevCronVo> cronList = redisCache.getCacheList(key);
//        if (cronList == null || cronList.isEmpty()) {
//            return AjaxResult.error("获取失败");
//        }
        return AjaxResult.success("获取成功", redisCache.getCacheList(key));
    }

    /**
     * 之前的设备离线，上线后若有设备分组任务则新增任务
     *
     * @author: 詹泽峰
     * @date: 2024/8/27 11:39
     * @param mac
     */
    @Override
    public void addCronWhenLogin(String mac, Integer devType) {
        SysDevInfo sysDevInfo = sysDevInfoService.getDeviceInfo(mac.toUpperCase());
        // 根据组名查询, 看是否有分组定时任务
        AlmGroupCron almGroupCron = almGroupCronMapper.selectOne(new QueryWrapper<AlmGroupCron>().lambda()
                .eq(AlmGroupCron::getGroupId, sysDevInfo.getDevGroupId()));
        // 如果有分组任务且该设备目前没有分组任务的设置
        if(almGroupCron != null && !sysDevInfo.getHasGroupCron()) {
            String command = DataUtils.setCommand(mac, Misc.int2hexStr2(devType), "91",
                    almGroupCron.getCronData());
            boolean isSuccess = SendMessage.sendMessage(ByteUtils.hexStrToBytes(command), mac);
            // 更改设备分组任务状态
            if (isSuccess) {
                sysDevInfoService.updateHasGroupCron(mac, true);
                log.info("新增设备分组定时任务命令发送成功");
            } else {
                log.info("新增设备分组定时任务命令发送失败");
            }
        }
    }

    /**
     * 将任务应用于设备对应设备分组
     *
     * @author: 詹泽峰
     * @date: 2024/8/26 16:03
     * @param rq
     * @return com.alm.common.core.domain.AjaxResult
     */
    @Override
    public AjaxResult setCronByDevGroup(DevCronEditRq rq) {
        Long userId = SecurityUtils.getUserId();
        if (userId == null) {
            throw new ServiceException("无法获取用户信息");
        }
        StringBuffer data = new StringBuffer();
        // data区设置id为"B4",Msgid为"01"
        data.append("B401");
        DataUtils.appendCronData(data, "C1", Misc.int2hexStr4(rq.getCronId()).toUpperCase());
        DataUtils.appendCronData(data, "C2", com.alm.handle.util.Misc.long2hexStr8(rq.getCronStartDateTime())
                .toUpperCase());
        DataUtils.appendCronData(data, "C3", rq.getCronFunction().toUpperCase());
        String cronParam = com.alm.handle.util.Misc.long2hexStr8(rq.getCronEndDateTime()) +
                rq.getCronParam();
        DataUtils.appendCronData(data, "C4", Misc.int2hexStr2(rq.getCronParam().length() / 2)
                .toUpperCase() + cronParam.toUpperCase());
//        DataUtils.appendCronData(data, "C5", rq.getCronParam());
        DataUtils.appendCronData(data, "C6", Misc.int2hexStr2(rq.getCycleType()).toUpperCase());
        DataUtils.appendCronData(data, "C7", com.alm.handle.util.Misc.long2hexStr8(rq.getCronEndDateTime())
                .toUpperCase());
        DataUtils.appendCronData(data, "C8", com.alm.handle.util.Misc.long2hexStr8(rq.getCycleInterval())
                .toUpperCase());
        DataUtils.appendCronData(data, "C9", Misc.int2hexStr2(rq.getCronSwitch()).toUpperCase());
        // 查询该设备所属设备分组id
        SysDevInfo sysDevInfo = sysDevInfoService.getDeviceInfo(rq.getMac().toUpperCase());
        // 清空数据库原来该分组的定时任务
        almGroupCronMapper.delete(new QueryWrapper<AlmGroupCron>().lambda()
                .eq(AlmGroupCron::getGroupId, sysDevInfo.getDevGroupId()));
        // 新增该分组的定时任务
        AlmGroupCron almGroupCron = new AlmGroupCron();
        almGroupCron.setGroupId(sysDevInfo.getDevGroupId());
        almGroupCron.setCronData(data.toString().toUpperCase());
        int row = almGroupCronMapper.insert(almGroupCron);
        // 查询该分组下所有设备
        List<DevInfoListVO> sysDevInfoList = almDevGroupService.getDevInfoByGroupId(sysDevInfo.getDevGroupId());
        for (DevInfoListVO sysDevInfoListVO : sysDevInfoList) {
            // 对设备清空所有任务
            String clearCmdData = "B407";
            String clearCmd = DataUtils.setCommand(sysDevInfoListVO.getDevMac(),
                    Misc.int2hexStr2(sysDevInfoListVO.getDevType()).toUpperCase(), "91", clearCmdData);
            boolean isClearSuccess = SendMessage.sendMessage(ByteUtils.hexStrToBytes(clearCmd), rq.getMac());
            // 发送情况命令成功则重置设备基础信息的是否设置过设备分组任务状态
            if (isClearSuccess) {
                sysDevInfoService.updateHasGroupCron(sysDevInfoListVO.getDevMac(), false);
            }
            // 当该分组有设备在线，先给这些设备新增一波任务
            if (sysDevInfoListVO.getOnlineStatus() == 1) {
                String command = DataUtils.setCommand(rq.getMac(), rq.getDevType(), "91", data.toString());
                boolean isSuccess = SendMessage.sendMessage(ByteUtils.hexStrToBytes(command), rq.getMac());
                if (isClearSuccess) {
                    sysDevInfoService.updateHasGroupCron(sysDevInfoListVO.getDevMac(), true);
                }
            }
        }
        return row > 0 ? AjaxResult.success("添加设备分组定时任务成功") : AjaxResult.error("添加设备分组定时任务成功");
    }
}
